package com.lucenten.collect.gnss.handler.impl;

import cn.quevo.common.lang.DateFormatUtils;
import cn.quevo.common.lang.NumberUtils;
import cn.quevo.common.lang.StringUtils;
import cn.quevo.core.spring.util.SpringUtil;
import com.lucenten.collect.gnss.entity.GnssFile;
import com.lucenten.collect.gnss.entity.ObsErvation;
import com.lucenten.collect.gnss.entity.SatelliteStation;
import com.lucenten.collect.gnss.enums.FileSuffix;
import com.lucenten.collect.gnss.handler.AbstractGnssHandler;
import com.lucenten.collect.gnss.handler.GnssHandler;
import com.lucenten.collect.gnss.handler.tools.GnssContext;
import com.lucenten.collect.gnss.service.ObsErvationService;
import com.lucenten.collect.gnss.service.SatelliteStationService;
import com.lucenten.collect.utils.FileUtils;
import com.lucenten.mq.SendJmsInfo;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;

/**
 * 第五步：数据统计
 */
@Slf4j
public class StatisticsGnssHandler extends AbstractGnssHandler implements GnssHandler {
    public StatisticsGnssHandler(SatelliteStationService satelliteStationService, ObsErvationService obsErvationService) {
        super(satelliteStationService, obsErvationService);
    }

    @Override
    protected boolean doProcess(GnssFile gnssFile) {
        /*final Path oPath = Paths.get(super.getTempPath("o", gnssFile));
        try {
            Files.walkFileTree(oPath, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    if (FileUtils.getFileSuffix(file.getFileName().toString().toLowerCase()).equals(FileSuffix.O)) {
                        statistics(file, gnssFile);
//                        System.out.println("截止时间："+new Date().getTime());
                        return FileVisitResult.CONTINUE;
                    }
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                    return super.postVisitDirectory(dir, exc);
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }*/
        if (StringUtils.isEmpty(gnssFile.getDirFiles())) {
            return true;
        }
        Path oPath = null;
        for (String fileName : gnssFile.getDirFiles()) {
            if (!fileName.endsWith("o")) {
                continue;
            }
            oPath = Paths.get(super.getTempPath("o",gnssFile),fileName);
            if (Files.notExists(oPath)) {
                continue;
            }
            this.statistics(oPath, gnssFile);
        }
        return true;
    }

    // TODO 统计
    private void statistics(Path file, GnssFile gnssFile) {
        try {
            String fileName = file.getFileName().normalize().toString().toLowerCase();
            ObsErvation obsErvation = ObsErvation.getInstance(super.getSetationName(fileName), fileName, gnssFile.getDateStr(), gnssFile.getGnssType().getPath());
            if (Files.notExists(file) || Files.size(file) <= 0) {
                obsErvation.setFullYn("错误原因:文件为空");
                save(obsErvation);
                return;
            }
            List<String> lines = Files.readAllLines(file);
            if (StringUtils.isEmpty(lines) || StringUtils.isBlank(lines.get(0).trim())) {
                obsErvation.setFullYn("错误原因:文件为空");
                save(obsErvation);
                return;
            }
            String line = lines.get(0);
            if (line.length() < 60 || line.substring(60).trim().equals("") || !line.substring(60).trim().equalsIgnoreCase("RINEX VERSION / TYPE")) {
                obsErvation.setFullYn("错误原因:头文件是错的,没有RINEX VERSION / TYPE");
                save(obsErvation);
                return;
            }
            boolean isSuccess = true;
            String version = line.substring(5, 6);
            String endLine = "";
            SatelliteStation satelliteStation = gnssFile.getStation();
            for (int i = 1; i < lines.size(); i++) {
                line = lines.get(i);
                if (line.length() < 60) {
                    continue;
                }
                //这三个如果都没有，是正确的，如果有，且都不为空，则也是正确的，，，否则是错误的
                if (isTitle(line, "RCV CLOCK OFFS APPL")) {           //没有这一行是正确的，为空是错误的
                    if (isStartLengthNull(line, "RCV CLOCK OFFS APPL", obsErvation, 60)) {
                        return;
                    }
                    continue;
                }
                if (isTitle(line, "WAVELENGTH FACT L1/2")) {    //没有这一行是正确的，为空是错误的
                    if (isStartLengthNull(line, "WAVELENGTH FACT L1/2", obsErvation, 60)) {
                        return;
                    }
                    continue;
                }
                if (isTitle(line, "INTERVAL")) {                //没有这一行是正确的，为空是错误的
                    if (isStartLengthNull(line, "INTERVAL", obsErvation, 60)) {
                        return;
                    }
                    obsErvation.setInterval1(NumberUtils.toDouble(line.substring(0, 6).trim()));
                    continue;
                }
                // 获取结束时间
                if (isTitle(line, "TIME OF LAST OBS")) {
                    if (isStartLengthNull(line, "TIME OF LAST OBS", obsErvation, 35)) {
                        return;
                    }
                    /*endFileTime = allLine.substring(0, 6).trim()+"-"+allLine.substring(6, 12).trim()+"-"+allLine.substring(12, 18).trim()+" " +
                            allLine.substring(18, 24).trim()+":"+allLine.substring(24, 30).trim()+":"+allLine.substring(30, 35).trim()+" 000";*/
                    obsErvation.setEndFileTime(formatLineToDate(line));
                    continue;
                }
                endLine = line.substring(60).trim();
                if (endLine.equals("PGM / RUN BY / DATE")
                        || endLine.equals("MARKER NAME")
                        || endLine.equals("OBSERVER / AGENCY")
                        || endLine.equals("REC # / TYPE / VERS")
                        || endLine.equals("ANT # / TYPE")) {
                    isSuccess = false;
                    continue;
                }
                if (isTitle(line, "APPROX POSITION XYZ")) {                           //没有这一行是错误的
                    if (isStartLengthNull(line, "APPROX POSITION XYZ", obsErvation, 60)) {
                        return;
                    }
                    isSuccess = false;
                    if (!StringUtils.isBlank(line.substring(0,14).trim())) {
                        obsErvation.setX(NumberUtils.toDouble(line.substring(0,14).trim()));
                    }
                    if (!StringUtils.isBlank(line.substring(14, 28).trim())) {
                        obsErvation.setY(NumberUtils.toDouble(line.substring(14, 28).trim()));
                    }
                    if (!StringUtils.isBlank(line.substring(28, 42).trim())) {
                        obsErvation.setZ(NumberUtils.toDouble(line.substring(28, 42).trim()));
                    }
                    this.initXyz(obsErvation, satelliteStation);
                    continue;
                }
                if (isTitle(line, "ANTENNA: DELTA H/E/")) {     //没有这一行是错误的
                    if (isStartLengthNull(line, "ANTENNA: DELTA H/E/N", obsErvation, 60)) {
                        return;
                    }
                    isSuccess = false;
                    continue;
                }
                if (isTitle(line, "# / TYPES OF OBSERV")) {     //没有这一行是错误的
                    if (isStartLengthNull(line, "# / TYPES OF OBSERV", obsErvation, 6)) {
                        return;
                    }
                    isSuccess = false;
                    // 设置双频/单频
                    i = calculateObsFlag(i, lines, obsErvation, version);
                    continue;
                }
                if (isTitle(line, "SYS / # / OBS TYPES")) { //没有这一行是错误的
                    if (isStartLengthNull(line, "SYS / # / OBS TYPES", obsErvation, 6)) {
                        return;
                    }
                    isSuccess = false;
                    // 设置双频/单频
                    i = calculateObsFlag(i, lines, obsErvation, "3");// 此处版本不会是2
                    continue;
                }
                if (isTitle(line, "TIME OF FIRST OBS")) {//没有这一行是错误的
                    if (line.substring(0, 60).trim().equalsIgnoreCase("")) {
                        continue;
                    }
                    obsErvation.setBeginFileTime(formatLineToDate(line));
                }
                if (line.substring(60, line.length()).trim().equals("END OF HEADER")) {
                    isSuccess = false;
                    break;
                }
            }
            if (StringUtils.isBlank(obsErvation.getX())
                    || StringUtils.isBlank(obsErvation.getY())
                    || StringUtils.isBlank(obsErvation.getZ())
                    || StringUtils.isBlank(obsErvation.getObsFlag())
                    || isSuccess) {
                obsErvation.setFullYn("错误原因:没有必须的文件头信息");
                save(obsErvation);
                return;
            }
            obsErvation.setFullYn("完整");
            obsErvation.setTrueYn("正确");
            save(obsErvation);
        } catch (IOException e) {
            SendJmsInfo.sendGnssMq(12, file.getFileName().normalize().toString(), 1);
            log.error("O文件内容解析异常:" + file.normalize().toString(), e);
        }
    }

    private void initXyz(ObsErvation obsErvation, SatelliteStation satelliteStation) {
        boolean update = false;
        if (StringUtils.isBlank(obsErvation.getX()) && !StringUtils.isBlank(satelliteStation.getX())) {
            obsErvation.setX(satelliteStation.getX());
        }
        if (StringUtils.isBlank(obsErvation.getY()) && !StringUtils.isBlank(satelliteStation.getY())) {
            obsErvation.setY(satelliteStation.getY());
        }
        if (StringUtils.isBlank(obsErvation.getZ()) && !StringUtils.isBlank(satelliteStation.getZ())) {
            obsErvation.setZ(satelliteStation.getZ());
        }
        if (StringUtils.isBlank(satelliteStation.getX()) && !StringUtils.isBlank(obsErvation.getX())) {
            update = true;
            satelliteStation.setX(obsErvation.getX());
        }
        if (StringUtils.isBlank(satelliteStation.getY()) && !StringUtils.isBlank(obsErvation.getY())) {
            update = true;
            satelliteStation.setY(obsErvation.getY());
        }
        if (StringUtils.isBlank(satelliteStation.getZ()) && !StringUtils.isBlank(obsErvation.getZ())) {
            update = true;
            satelliteStation.setZ(obsErvation.getZ());
        }
        if (update) {
//            SatelliteStationService satelliteStationService = SpringUtil.getBean("satelliteStationService");
            satelliteStationService.update(satelliteStation);
        }
    }

    private void statisticsData(int index, List<String> lines, ObsErvation obsErvation) {
        if (lines.size() <= index || StringUtils.isBlank(lines.get(index))) {
            obsErvation.setFullYn("错误原因:没有观测数据");
            save(obsErvation);
            return;
        }
        String line = "";
        String year = "";
        //存放当前文件内出现的所有时间
        List<Long> listFileTime = new ArrayList<Long>();
        for (int i = index; i < lines.size(); i++) {
            line = lines.get(i);
            if (line.length() <= 29) {
                continue;
            }
            if (!line.substring(26, 29).trim().equals("0") && !line.substring(26, 29).trim().equals("1")) {
                continue;
            }
            year = line.substring(0, 3).trim();
            if (year.length() == 1) {
                year = obsErvation.getYear().substring(0, 2) + "0" + year;
            } else if (year.length() == 2) {
                year = obsErvation.getYear().substring(0, 2) + year;
            }
            String perFileTime = year + line.substring(3, 6).trim() + line.substring(6, 9).trim() + line.substring(9, 12).trim() + line.substring(12, 15).trim();
            try {
                int second = (int) Math.round(Double.parseDouble(line.substring(15, 26).trim()));
                perFileTime = perFileTime + second;
                long time = DateFormatUtils.parse(perFileTime, "yyyyMMddHHmmss").getTime();
                if (time == 0) {       //数据文件内的时间错误
                    obsErvation.setFullYn("错误原因:观测数据中的时间错误");
                    save(obsErvation);
                    return;
                }
                listFileTime.add(time);
            } catch (NumberFormatException e1) {
                obsErvation.setFullYn("错误原因:观测数据中的时间错误");
                save(obsErvation);
                return;
            } catch (Exception e) {
                obsErvation.setFullYn("错误原因:观测数据中的时间错误");
                save(obsErvation);
                return;
            }
        }
        if (listFileTime.size() < 2) {
            obsErvation.setFullYn("错误原因:判断不出采样率");
            return;
        }
        // 已经读到第二个时间了
        // 判断间隔是否为0，为0则说明，从头文件中没有读到时间间隔
        if (listFileTime.size() >= 2 && obsErvation.getInterval1().doubleValue() == 0) {
            obsErvation.setInterval1((listFileTime.get(1) - listFileTime.get(0)) / 1000d);
        }
        /**
         * 验证时间连续性
         */
        this.statisticFileInfo(listFileTime, obsErvation);
    }

    /**
     * 验证时间连续性
     *
     * @param listFileTime
     * @param obsErvation
     */
    public void statisticFileInfo(List<Long> listFileTime, ObsErvation obsErvation) {
        //开始时间
        long beginFileTimeLong = DateFormatUtils.parse(obsErvation.getBeginFileTime(), "yyyyMMddHHmmss").getTime();

        List<Long> max = new ArrayList<Long>();                    //根据开始时间、结束时间和间隔的秒数，组成的最大的集合
        if (!"".equalsIgnoreCase(obsErvation.getEndFileTime())) {
            long endFileTimeLong = DateFormatUtils.parse(obsErvation.getEndFileTime(), "yyyy-MM-dd HH:mm:ss SSS").getTime();
            for (long i = beginFileTimeLong; i <= endFileTimeLong; i += obsErvation.getInterval1() * 1000) {
                max.add(i);
            }
            this.isTimeComplete(obsErvation, listFileTime, max);
            return;
        }
        long _begin = beginFileTimeLong;
        max.clear();
        int count = (int) (30 * 60 / obsErvation.getInterval1());
        for (int i = 0; i < count; i++) {
            max.add(_begin);
            _begin += obsErvation.getInterval1() * 1000;
        }
        if (max.containsAll(listFileTime)) {
            if (max.size() == listFileTime.size()) {
                obsErvation.setFullYn("完整");
                obsErvation.setTrueYn("正确");
                save(obsErvation);
                return;
            }
            obsErvation.setFullYn("不完整:文件信息不完整，无观测数据");
            save(obsErvation);
            return;
        }
        _begin = beginFileTimeLong;
        max.clear();
        count = (int) (60 * 60 / obsErvation.getInterval1());
        for (int i = 0; i < count; i++) {
            max.add(_begin);
            _begin += obsErvation.getInterval1() * 1000;
        }
        isTimeComplete(obsErvation, listFileTime, max);
    }

    /**
     * 判断文件是否完整
     */
    private void isTimeComplete(ObsErvation obsErvation, List<Long> listFileTime, List<Long> max) {
        if (!max.containsAll(listFileTime)) {
            obsErvation.setFullYn("错误原因:观测数据中的时间错误");
            save(obsErvation);
            return;
        }
        if (max.size() == listFileTime.size()) {
            obsErvation.setFullYn("完整");
            obsErvation.setTrueYn("正确");
            save(obsErvation);
            return;
        }
        obsErvation.setFullYn("不完整:文件信息不完整，无观测数据");
        save(obsErvation);
    }

    /**
     * 验证是否包含标题
     *
     * @param line
     * @param title
     * @return
     */
    private boolean isTitle(String line, String title) {
        return line.substring(60).trim().contains(title);
    }

    /**
     * 将字符串格式化日期字符串
     *
     * @param line
     * @return
     */
    private String formatLineToDate(String line) {
        StringBuilder builder = new StringBuilder(line.substring(0, 6).trim());//年
        builder.append(line.substring(6, 12).trim());//月
        builder.append(line.substring(12, 18).trim());// 日
        builder.append(line.substring(18, 24).trim());// 时
        builder.append(line.substring(24, 30).trim());//分
        builder.append(line.substring(30, 35).trim());//秒
        return builder.toString();
    }

    /**
     * 验证字符串到截至位置是否为空
     *
     * @param line
     * @param title
     * @param obsErvation
     * @param end
     * @return
     */
    private boolean isStartLengthNull(String line, String title, ObsErvation obsErvation, int end) {
        if (line.substring(0, end).trim().equalsIgnoreCase("")) {
            obsErvation.setFullYn("错误原因：" + title + "为空是错误的");
            save(obsErvation);
            return true;
        }
        return false;
    }

    /**
     * 计算是否双频
     *
     * @param index
     * @param lines
     * @param obsErvation
     * @param version
     * @return
     */
    private int calculateObsFlag(int index, List<String> lines, ObsErvation obsErvation, String version) {
        String line = lines.get(index);
        int obsTypeNum = "2".equalsIgnoreCase(version) ? NumberUtils.toInt(line.substring(0, 6).trim()) : NumberUtils.toInt(line.substring(4, 6).trim());
        int begin = "2".equalsIgnoreCase(version) ? 6 : 7;
        int end = "2".equalsIgnoreCase(version) ? 60 : 40;
        StringBuilder obsTypes = new StringBuilder(line.substring(begin, end));
        if (obsTypeNum < 10) {
            setObsFlag(obsTypes.toString(), obsErvation, obsTypeNum);
            return index;
        }
        int max = obsTypeNum % 10 == 0 ? obsTypeNum / 10 : obsTypeNum / 10 + 1;
        for (int i = 1; i <= max; i++) {
            index += 1;
            obsTypes.append(lines.get(index).substring(begin, end));
        }
        setObsFlag(obsTypes.toString(), obsErvation, obsTypeNum);
        return index;
    }

    /**
     * 设置双频/单频
     *
     * @param obsType
     * @param obsErvation
     */
    private void setObsFlag(String obsType, ObsErvation obsErvation, int obsTypeNum) {
        //根据观测类型判断是否是双频
        List<String> obsTypeList = new ArrayList<String>();
        String[] obsTypeArray = new String[obsTypeNum];
        for (int i = 0; i < obsTypeNum; i++) {
            obsTypeArray[i] = obsType.substring(i * 6, i * 6 + 6).trim();
            obsTypeList.add(obsTypeArray[i]);
        }
        if (obsTypeList.containsAll(GnssContext.OBS_TYPE_A) ||
                obsTypeList.containsAll(GnssContext.OBS_TYPE_B)) {
            obsErvation.setObsFlag("双频");
            return;
        }
        obsErvation.setObsFlag("单频");
    }

    /**
     * 保存入库
     *
     * @param obsErvation
     * @author July july_sky@foxmail.com
     * @date 2019/4/28 22:28
     */
    private void save(ObsErvation obsErvation) {
//        ObsErvationService obsErvationService = SpringUtil.getBean("obsErvationService");
        obsErvationService.create(obsErvation);
//        SendJmsInfo.sendGnssMq(12, obsErvation.getFileName(), 0);
    }
}
